/*
 * Copyright 2008-2010 Daniel Cachapa <cachapa@gmail.com>
 * 
 * This program is distributed under the terms of the GNU General Public License Version 3
 * The license can be read in its entirety in the LICENSE.txt file accompanying this source code,
 * or at: http://www.gnu.org/copyleft/gpl.html
 * 
 * This file is part of Libra.
 *
 * WeightWatch is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * WeightWatch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the WeightWatch source code. If not, see: http://www.gnu.org/licenses
 */

package net.cachapa.libra;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Locale;

import com.admob.android.ads.AdManager;

import net.cachapa.libra.adapter.ChartImageAdapter;
import net.cachapa.libra.component.ChartGallery;
import net.cachapa.libra.dailyburn.DailyBurnApi;
import net.cachapa.libra.dailyburn.Synchronizer;
import net.cachapa.libra.data.Database;
import net.cachapa.libra.data.Value;
import net.cachapa.libra.util.Bmi;
import net.cachapa.libra.util.ProMode;
import net.cachapa.libra.util.MyDate;
import net.cachapa.libra.util.UnitManager;
import net.cachapa.libra.util.Util;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.text.Html;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Gallery;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;

public class Main extends Activity implements OnItemSelectedListener, OnItemClickListener, OnItemLongClickListener {
	public static final int CHART_TYPE_WEEK = 0;
	public static final int CHART_TYPE_MONTH = 1;
	public static final int CHART_TYPE_30_DAY = 2;
	public static final int CHART_TYPE_YEAR = 3;
	public static final int CHART_TYPE_COMPLETE = 4;
	
	private static final int MENU_INSERT_VALUE = 10;
	private static final int MENU_SHARE_CHART = 11;
	private static final int MENU_CHART_TYPE = 12;
	private static final int MENU_SYNC = 13;
	private static final int MENU_PREFERENCES = 14;
	private static final int DIALOG_LOGGED_IN = 20;
	private static final int DIALOG_FIRST_TIME = 21;
	private static final int DIALOG_CHANGELOG = 22;
	private static final int DIALOG_CHART_TYPE = 23;
	
	private static final int CHART_PADDING = 20;
	
	private static final String BACKUP_DIR = "/.Libra";
	
	private MyDate date;
	private int chartType;
	private int chartWidth = 0, chartHeight = 0;
	private boolean synching = false;
	
	/** Called when the activity is first created. */
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		
		if (ProMode.isInProMode(this)) {
			setContentView(R.layout.main);
		}
		else {
			setContentView(R.layout.main_ad);
			AdManager.setTestDevices(new String[] {
					AdManager.TEST_EMULATOR,			// Android emulator
	//				"", // My phone
			});
		}
		
		date = new MyDate();
				
		ChartGallery gallery = (ChartGallery) findViewById(R.id.ChartGallery);
		gallery.setParent(this);
		gallery.setCallbackDuringFling(false);
		gallery.setOnItemSelectedListener(this);
		gallery.setOnItemClickListener(this);
		gallery.setOnItemLongClickListener(this);
		
		String version = null;
		try {
			version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		Editor editor = prefs.edit();
		String prefsVersion = prefs.getString(Preferences.VERSION, null);
		
		if (!version.equals(prefsVersion)) {
			// Then we're upgrading, so we show the changelog
			editor.putString(Preferences.VERSION, version);
			editor.commit();
			showDialog(DIALOG_CHANGELOG);
		}
		
		if (prefsVersion == null) {
			// Then it's the first time the application is running
			// First we set the units according to the current locale
			String country = Locale.getDefault().getCountry();
			if (country.equalsIgnoreCase("gb") || country.equalsIgnoreCase("us")) {
				editor.putString(Preferences.HEIGHT_UNITS, "feet");
				editor.putString(Preferences.WEIGHT_UNITS, "pounds");
				editor.commit();
			}
			else {
				editor.putString(Preferences.HEIGHT_UNITS, "meters");
				editor.putString(Preferences.WEIGHT_UNITS, "kilograms");
				editor.commit();
			}
			
			// Now we show the welcome dialog
			showDialog(DIALOG_FIRST_TIME);
		}
		
		// Check if we need to backup the database
		if (prefs.getBoolean(Preferences.AUTO_BACKUP, true)) {
			MyDate today = new MyDate();
			String lastBackup = prefs.getString(Preferences.LAST_BACKUP_DATE, "1970-01-01");
			MyDate lastBackupDate = new MyDate(lastBackup);
			
			if (lastBackupDate.differenceInDays(today) >= 7) {
				new DatabaseBackerUpper().execute(0);
				editor.putString(Preferences.LAST_BACKUP_DATE, today.toStandardString());
				editor.commit();
				
				deleteExtraBackups();
			}
		}
		
		// Retrieve the last chart type
		chartType = prefs.getInt(Preferences.CHART_TYPE, CHART_TYPE_MONTH);
		// Sanity check -- if the chart type doesn't correspond to one of the available types, then reset
		if (chartType < 0 || chartType > CHART_TYPE_COMPLETE) {
			chartType = CHART_TYPE_MONTH;
		}
		
		Configuration conf = (Configuration) getLastNonConfigurationInstance();
		if (conf != null) {
			date = conf.date;
		}
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		// Testing if we're coming back from the DailyBurn login page
		try {
			Uri uri = getIntent().getData();
			if (uri != null && uri.toString().startsWith(DailyBurnApi.CALLBACK_URI) && !DailyBurnApi.getInstance(this).isLoggedIn()) {
				// This means we're successfully logged in
				// All that's left is to complete the login procedure
				DailyBurnApi.getInstance(this).completeLogin(uri);
				showDialog(DIALOG_LOGGED_IN);
			}
			else {
				SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
				if (DailyBurnApi.getInstance(this).isLoggedIn() && prefs.getBoolean(Preferences.AUTO_SYNC, false)) {
					Database database = Database.getInstance(this);
					if (database.getSizeUnsynchedValues() > 0) {
						new BodyEntriesUploader().execute(0);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		refreshChart();
	}
	
	@Override
	public Object onRetainNonConfigurationInstance() {
		Configuration conf = new Configuration();
		conf.date = date;
		return conf;
	}
	
	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_LOGGED_IN:
			return new AlertDialog.Builder(this)
			.setIcon(android.R.drawable.ic_dialog_info)
			.setTitle(R.string.logged_in_msg)
			.setMessage(R.string.sync_now_question)
			.setPositiveButton(R.string.synchronize, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					new BodyEntriesSynchronizer().execute(0);
				}
			})
			.setNegativeButton(R.string.later, null)
			.create();
			
		case DIALOG_FIRST_TIME:
			return new AlertDialog.Builder(this)
			.setTitle(R.string.welcome_to_libra)
			.setMessage(R.string.welcome_to_libra_msg)
			.setPositiveButton(R.string.close, null)
			.create();
			
		case DIALOG_CHANGELOG:
			StringBuilder changelog = new StringBuilder();
			BufferedReader input;
			try {
				InputStream is = getResources().openRawResource(R.raw.changelog);
				input = new BufferedReader(new InputStreamReader(is));
				String line;
				while ((line = input.readLine()) != null) {
					changelog.append(line);
					changelog.append("<br/>");
				}
				input.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			return new AlertDialog.Builder(this)
			.setTitle(R.string.changelog_title)
			.setMessage(Html.fromHtml(changelog.toString()))
			.setPositiveButton(R.string.close, null)
			.create();
			
		case DIALOG_CHART_TYPE:
			return new AlertDialog.Builder(this)
			.setTitle(R.string.chart_type)
			.setSingleChoiceItems(R.array.chartTypes, chartType,
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog,	int whichButton) {
					date = new MyDate();
					chartType = whichButton;
					Editor editor = PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit();
					editor.putInt(Preferences.CHART_TYPE, chartType);
					editor.commit();
					refreshChart();
					dialog.dismiss();
				}
			}).create();
		}
		return null;
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if ((keyCode == KeyEvent.KEYCODE_BACK)) {
			finish();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
	
	public void onGallerySizeChanged(int w, int h) {
		if (w == 0 || h == 0) {
			return;
		}
		chartWidth = w - CHART_PADDING;
		chartHeight = h - CHART_PADDING;
		refreshChart();
	}
	
	@Override
	public void onLowMemory() {
		// Trying to be nice and releasing all of our cached bitmaps.
		// Not sure if this works, though...
		refreshChart();
		super.onLowMemory();
	}
	
	private void refreshChart() {
		// TODO Determine if the charts need to be refreshed.
		
		if (chartWidth > 0) {
			switch (chartType) {
			case CHART_TYPE_WEEK:
				refreshWeekChart();
				break;
			case CHART_TYPE_MONTH:
				refreshMonthChart();
				break;
			case CHART_TYPE_30_DAY:
				refresh30DayChart();
				break;
			case CHART_TYPE_YEAR:
				refreshYearChart();
				break;
			case CHART_TYPE_COMPLETE:
				refreshCompleteChart();
				break;
			}
		}
		
		TextView trendTextView = (TextView) findViewById(R.id.TrendTextView);
		if (trendTextView == null) {
			// Then we're in landscape mode
			return;
		}
		
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		Database database = Database.getInstance(this);
		Value latestValue = database.getLatestValue();
		UnitManager um = UnitManager.getInstance(this);
		
		// Current trend
		if (latestValue != null) {
			trendTextView.setText(um.toWeightUnit(latestValue.getTrend()));
		}
		else {
			trendTextView.setText(R.string.not_available);
		}
		
		// BMI
		TextView bmiTextView = (TextView) findViewById(R.id.BmiTextView);
		View bmiLayout = (View) findViewById(R.id.BmiLayout);
		bmiLayout.setVisibility(View.GONE);
		float bmi = 0;
		if (latestValue != null) {
			float userHeight = prefs.getFloat("heightPreference", 0);
			if (userHeight > 0) {
				bmiLayout.setVisibility(View.VISIBLE);
				bmi = Bmi.calculateBMI(latestValue.getTrend(), userHeight, um.isMetricHeight(), um.isMetricWeight());
				bmiTextView.setText(Util.Round(bmi, 1) + " (" + Bmi.getLevelName(bmi, this) + ")");
			}
		}
		
		// 7-day weight change
		float trendChange = 0;
		if (latestValue != null) {
			MyDate sevenDaysPrior = new MyDate(latestValue.getDate());
			sevenDaysPrior.addDays(-1);
			Value trendSevenDaysPrior = database.getTrendAtDate(sevenDaysPrior);
			trendChange = latestValue.getTrend() - trendSevenDaysPrior.getTrend();
		}
		float energyChange = um.getKCal() * trendChange;
		String positiveSign = "";
		if (energyChange > 0) {
			positiveSign = "+";
		}
		TextView sevenDayTextView = (TextView) findViewById(R.id.SevenDayWeightChangeTextView);
		String weightPerWeek = positiveSign + String.format(getString(R.string.weight_per_week), um.toWeightUnit(trendChange*7));
		sevenDayTextView.setText(weightPerWeek + " (" + positiveSign + Util.Round(energyChange, 1) + " " + getString(R.string.kcal_per_day) + ")");
		
		// Update the goal weight and projected goal date
		TextView goalWeightTextView = (TextView) findViewById(R.id.GoalWeightTextView);
		TextView expectedDateTextView = (TextView) findViewById(R.id.ExpectedDateTextView);
		View goalLayout = (View) findViewById(R.id.GoalLayout);
		View expectedDateLayout = (View) findViewById(R.id.ExpectedDateLayout);
		goalLayout.setVisibility(View.GONE);
		expectedDateLayout.setVisibility(View.GONE);
		float goalWeight = prefs.getFloat("goalWeightPreference", 0);
		if ((goalWeight > 0) && latestValue != null) {
			goalLayout.setVisibility(View.VISIBLE);
			goalWeightTextView.setText(um.toWeightUnit(goalWeight));
			if (prefs.getBoolean("showExpectedDatePreference", true)) {
				expectedDateLayout.setVisibility(View.VISIBLE);
				Value goalValue = database.getGoalValue();
				if (goalValue == null || goalValue.getTrend() != goalWeight) {
					expectedDateTextView.setText(R.string.expected_unknown);
				}
				else {
					expectedDateTextView.setText(goalValue.getDate().toMediumString());
				}
			}
		}
	}
	
	private void refreshWeekChart() {
		ChartImageAdapter chartAdapter = new ChartImageAdapter(this, chartWidth, chartHeight, CHART_TYPE_WEEK);
		Database database = Database.getInstance(this);
		Value firstValue = database.getFirstValue();
		MyDate today = new MyDate();
		if (firstValue != null) {
			MyDate startDate = firstValue.getDate();
			startDate.backToFirstDayOfWeek();
			MyDate endDate = database.getLatestValue().getDate();
			if (endDate.isBefore(today)) {
				endDate = today;
			}
			endDate.addDays(1);
			while(startDate.isBefore(endDate)) {
				chartAdapter.addChart(startDate);
				startDate.addDays(7);
			}
		}
		else {
			today.backToFirstDayOfWeek();
			chartAdapter.addChart(today);
		}
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		gallery.setAdapter(chartAdapter);
		today.backToFirstDayOfWeek();
		gallery.setSelection(chartAdapter.getPosition(today), false);
	}
	
	private void refreshMonthChart() {
		ChartImageAdapter chartAdapter = new ChartImageAdapter(this, chartWidth, chartHeight, CHART_TYPE_MONTH);
		Database database = Database.getInstance(this);
		Value firstValue = database.getFirstValue();
		MyDate today = new MyDate();
		if (firstValue != null) {
			MyDate startDate = firstValue.getDate();
			startDate.setDay(1);
			MyDate endDate = database.getLatestValue().getDate();
			if (endDate.isBefore(today)) {
				endDate = today;
			}
			endDate.setDay(endDate.getDaysInMonth());
			while(startDate.isBefore(endDate)) {
				chartAdapter.addChart(startDate);
				startDate.goForwardOneMonth();
			}
		}
		else {
			chartAdapter.addChart(today);
		}
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		gallery.setAdapter(chartAdapter);
		gallery.setSelection(chartAdapter.getPosition(date), false);
	}
	
	private void refresh30DayChart() {
		ChartImageAdapter chartAdapter = new ChartImageAdapter(this, chartWidth, chartHeight, CHART_TYPE_30_DAY);
		chartAdapter.addChart(null);
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		gallery.setAdapter(chartAdapter);
		gallery.setSelection(chartAdapter.getPosition(date), false);
	}
	
	private void refreshYearChart() {
		ChartImageAdapter chartAdapter = new ChartImageAdapter(this, chartWidth, chartHeight, CHART_TYPE_YEAR);
		Database database = Database.getInstance(this);
		Value firstValue = database.getFirstValue();
		MyDate today = new MyDate();
		if (firstValue != null) {
			MyDate startDate = firstValue.getDate();
			startDate.setDay(1);
			startDate.setMonth(1);
			MyDate endDate = database.getLatestValue().getDate();
			if (endDate.isBefore(today)) {
				endDate = today;
			}
			endDate.setDay(31);
			endDate.setMonth(12);
			while(startDate.isBefore(endDate)) {
				chartAdapter.addChart(startDate);
				startDate.setYear(startDate.getYear() + 1);
			}
		}
		else {
			chartAdapter.addChart(today);
		}
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		gallery.setAdapter(chartAdapter);
		gallery.setSelection(chartAdapter.getCount()-1, true);
	}
	
	private void refreshCompleteChart() {
		ChartImageAdapter chartAdapter = new ChartImageAdapter(this, chartWidth, chartHeight, CHART_TYPE_COMPLETE);
		chartAdapter.addChart(null);
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		gallery.setAdapter(chartAdapter);
		gallery.setSelection(chartAdapter.getPosition(date), false);
	}
	
	public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
		Gallery gallery = (Gallery) findViewById(R.id.ChartGallery);
		ChartImageAdapter adapter = (ChartImageAdapter) gallery.getAdapter();
		date = adapter.getDate(position);
		
		TextView trendTextView = (TextView) findViewById(R.id.TrendTextView);
		if (trendTextView == null) {
			// Then we're in landscape mode
			return;
		}
		
		Database database = Database.getInstance(this);
		MyDate chartDate = null;
		if (date != null) {
			chartDate = new MyDate(date);
		}
		Value t1 = null, t2 = null;
		String label = null;
		float value = 0;
		// Update the weight change label
		switch (chartType) {
		case CHART_TYPE_WEEK:
			chartDate.backToFirstDayOfWeek();
			t1 = database.getTrendAtDate(chartDate);
			chartDate.addDays(7);
			t2 = database.getTrendAtDate(chartDate);
			label = getString(R.string.trend_variation_week);
			break;
		case CHART_TYPE_MONTH:
			chartDate.setDay(1);
			t1 = database.getTrendAtDate(chartDate);
			chartDate.setDay(chartDate.getDaysInMonth());
			t2 = database.getTrendAtDate(chartDate);
			label = String.format(getString(R.string.trend_variation_in), chartDate.getMonthName());
			break;
		case CHART_TYPE_30_DAY:
			MyDate endDate = new MyDate();
			MyDate startDate = new MyDate(endDate);
			startDate.addDays(-30);
			t1 = database.getTrendAtDate(startDate);
			t2 = database.getTrendAtDate(endDate);
			label = getString(R.string.trend_variation);
			break;
		case CHART_TYPE_YEAR:
			chartDate.setDay(1);
			chartDate.setMonth(1);
			t1 = database.getTrendAtDate(chartDate);
			chartDate.setDay(31);
			chartDate.setMonth(12);
			t2 = database.getTrendAtDate(chartDate);
			label = String.format(getString(R.string.trend_variation_in), chartDate.getYear());
			break;
		case CHART_TYPE_COMPLETE:
			if (!database.isEmpty()) {
				chartDate = database.getFirstValue().getDate();
				t1 = database.getTrendAtDate(chartDate);
				chartDate = database.getLatestValue().getDate();
				t2 = database.getTrendAtDate(chartDate);
				label = getString(R.string.trend_variation);
			}
			break;
		}
		UnitManager um = UnitManager.getInstance(this);
		if (t1 != null && t2 != null) {
			value = t2.getTrend() - t1.getTrend();
		}
		TextView weightChangeLabelTextView = (TextView) findViewById(R.id.WeightChangeLabelTextView);
		weightChangeLabelTextView.setText(label);
		String positiveSign = "";
		if (value > 0) {
			positiveSign = "+";
		}
		TextView weightChangeValueTextView = (TextView) findViewById(R.id.WeightChangeValueTextView);
		weightChangeValueTextView.setText(positiveSign + um.toWeightUnit(value));
	}

	public void onNothingSelected(AdapterView<?> v) {
		// Not needed
	}
	
	public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
		MyDate itemDate = ((ChartImageAdapter)parent.getAdapter()).getDate(position);
		Intent databaseListIntent = new Intent(this, net.cachapa.libra.DatabaseList.class);
		switch (chartType) {
		case CHART_TYPE_WEEK:
			databaseListIntent.putExtra("day", itemDate.getDay());
			databaseListIntent.putExtra("month", itemDate.getMonth());
			databaseListIntent.putExtra("year", itemDate.getYear());
			break;
			
		case CHART_TYPE_MONTH:
			databaseListIntent.putExtra("month", itemDate.getMonth());
			databaseListIntent.putExtra("year", itemDate.getYear());
			break;
			
		case CHART_TYPE_YEAR:
			databaseListIntent.putExtra("year", itemDate.getYear());
			break;
		}
		startActivity(databaseListIntent);
	}
	
	public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
		Intent insertValueIntent = new Intent(this, net.cachapa.libra.InsertValue.class);
		startActivity(insertValueIntent);
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		menu.add(0, MENU_INSERT_VALUE, 1, R.string.insert_value).setIcon(
				android.R.drawable.ic_menu_add);
		menu.add(0, MENU_SHARE_CHART, 2, R.string.share_chart).setIcon(
				android.R.drawable.ic_menu_share);
		menu.add(1, MENU_CHART_TYPE, 3, R.string.chart_type).setIcon(
				R.drawable.chart);
		if (DailyBurnApi.getInstance(this).isLoggedIn()) {
			menu.add(2, MENU_SYNC, 4, R.string.synchronize)
				.setIcon(R.drawable.ic_menu_refresh) // This image is only available for Android > 2.x
				.setEnabled(!synching);
		}
		menu.add(3, MENU_PREFERENCES, 5, R.string.preferences).setIcon(
				android.R.drawable.ic_menu_preferences);
		
		// Now remove the current chart mode from the menu
		menu.removeItem(chartType);
		
		return super.onPrepareOptionsMenu(menu);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case MENU_INSERT_VALUE:
			Intent insertValueIntent = new Intent(this, net.cachapa.libra.InsertValue.class);
			startActivity(insertValueIntent);
			return true;
		case MENU_SHARE_CHART:
			shareChart();
			return true;
		case MENU_CHART_TYPE:
			showDialog(DIALOG_CHART_TYPE);
			return true;
		case MENU_SYNC:
			new BodyEntriesSynchronizer().execute(0);
			return true;
		case MENU_PREFERENCES:
			Intent preferencesIntent = new Intent(this,
					net.cachapa.libra.Preferences.class);
			startActivity(preferencesIntent);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	
	private void shareChart() {
		// Generate a chart image
		ChartImageAdapter cim = new ChartImageAdapter(this, 400, 320, chartType);
		Bitmap chart = cim.generateLabeledChart(date, true);
		
		// Save the image to the SD Card
		String path = Environment.getExternalStorageDirectory() + "/Libra.png";
		FileOutputStream out;
		
		try {
			out = new FileOutputStream(path);
			chart.compress(CompressFormat.PNG, 100, out);
			out.close();
		} catch (FileNotFoundException e) {
			Toast.makeText(this, "Error: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
			e.printStackTrace();
			return;
		} catch (IOException e) {
			Toast.makeText(this, "Error: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
			e.printStackTrace();
			return;
		}
		
		Toast.makeText(this, String.format(getString(R.string.chart_saved), path), Toast.LENGTH_LONG).show();
		
		// Create the intent to send the image
		Intent shareChartIntent = new Intent(Intent.ACTION_SEND);
		shareChartIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + path));
		shareChartIntent.setType("image/png");
		startActivity(Intent.createChooser(shareChartIntent, getString(R.string.share_chart)));
	}
	
	private void deleteExtraBackups() {
		// Check the backup directory and delete the older files
		String path = Environment.getExternalStorageDirectory() + BACKUP_DIR;
		File dir = new File(path);
		FilenameFilter filter = new FilenameFilter() {
			public boolean accept(File dir, String filename) {
				return filename.startsWith("Backup_");
			}
		};
		
		String[] children = dir.list(filter);
		if (children == null || children.length <= 5) {
			// Either dir does not exist, it is not a directory, or there at most 5 backups
			return;
		}
		
		// Sort the files so that we get the oldest ones on top
		Arrays.sort(children);
		// And now delete the top ones until only 5 are left
		for (int i = 0; i < (children.length - 5); i++) {
			File f = new File(path + "/" + children[i]);
			try {
				f.delete();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	
	private class Configuration {
		private MyDate date;
//		private int chartType;
	}
	
	
	
	private class BodyEntriesSynchronizer extends AsyncTask<Integer, Integer, String> {
		private ProgressDialog progressDialog;
		@Override
		protected void onPreExecute() {
			synching  = true;
			setProgressBarIndeterminateVisibility(synching);
			progressDialog = ProgressDialog.show(Main.this, getString(R.string.synchronization), getString(R.string.importing_values_dailyburn), true);
		}
		
		protected String doInBackground(Integer... params) {
			return Synchronizer.importEntries(getBaseContext());
		}
		
		protected void onPostExecute(String message) {
			synching = false;
			setProgressBarIndeterminateVisibility(synching);
			progressDialog.dismiss();
			Toast.makeText(getBaseContext(), message, Toast.LENGTH_LONG).show();
			refreshChart();
			Database database = Database.getInstance(getBaseContext());
			if (database.getSizeUnsynchedValues() > 0) {
				Toast.makeText(getBaseContext(), R.string.uploading_values, Toast.LENGTH_SHORT).show();
				new BodyEntriesUploader().execute(0);
			}
		}
	}
	
	private class BodyEntriesUploader extends AsyncTask<Integer, Integer, Integer> {
		@Override
		protected void onPreExecute() {
			synching  = true;
			setProgressBarIndeterminateVisibility(synching);
		}
		
		protected Integer doInBackground(Integer... params) {
			return Synchronizer.uploadEntries(getBaseContext());
		}
		
		protected void onPostExecute(Integer uploaded) {
			synching = false;
			setProgressBarIndeterminateVisibility(synching);
			switch (uploaded) {
			case -1:
				break;
			case 1:
				Toast.makeText(getBaseContext(), R.string.upload_complete_one, Toast.LENGTH_LONG).show();
				break;
			default:
				Toast.makeText(getBaseContext(),
						String.format(getString(R.string.upload_complete_many), uploaded),
						Toast.LENGTH_LONG).show();
				break;
			}
		}
	}
	
	private class DatabaseBackerUpper extends AsyncTask<Integer, Integer, Boolean> {
		@Override
		protected void onPreExecute() {
			setProgressBarIndeterminateVisibility(true);
			Toast.makeText(getBaseContext(), R.string.backing_up, Toast.LENGTH_SHORT).show();
		}
		
		protected Boolean doInBackground(Integer... params) {
			Database database = Database.getInstance(getBaseContext());
			String path = Environment.getExternalStorageDirectory() + BACKUP_DIR;
			String filename = "Backup_" + new MyDate().toStandardString() + ".csv";
			try {
				(new File(path)).mkdirs();
				database.exportToFile(path + "/" + filename);
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
			return true;
		}
		
		protected void onPostExecute(Boolean success) {
			if (!synching) {
				setProgressBarIndeterminateVisibility(false);
			}
			if (success) {
				Toast.makeText(getBaseContext(),
						"Database backed up", Toast.LENGTH_LONG).show();
			}
			else {
				Toast.makeText(getBaseContext(), "Error backing up the database", Toast.LENGTH_LONG).show();
			}
		}
	}
}